package net.pulseproject.router.config.dependency;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import net.pulseproject.router.config.parser.LineConfig;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class NaiveDependencySorter implements DependencySorter {
	
	private static final Log LOG = LogFactory.getLog(NaiveDependencySorter.class);
	
	// TODO LineConfigFilter has to be an interface and an explicit dependency (found via recursive failing unit tests)
	private final LineConfigFilter filter = new LineConfigFilter();
	
	
	@Override
	public final Collection<LineConfig> sortById(final Collection<LineConfig> configs) {
		if(configs == null) { throw new IllegalArgumentException("configs == null"); }
		LOG.debug("sortById(configs=" + Arrays.toString(configs.toArray()) + ")");
		
		final List<LineConfig> sortedConfigs = new ArrayList<LineConfig>(configs.size());
		final List<LineConfig> configsLeft = new ArrayList<LineConfig>(configs);
		
		while(sortedConfigs.size() != configs.size()) {
			final Collection<LineConfig> availableConfigs = this.filterAvailableConfigs(sortedConfigs, configsLeft);
			
			if(availableConfigs.isEmpty() == true) {
				throw new RuntimeException("Could not determine proper module order. " +
						"Given configurations were: " + Arrays.toString(configs.toArray()));
			}
			
			configsLeft.removeAll(availableConfigs);
			sortedConfigs.addAll(availableConfigs);
		}
		
		return Collections.unmodifiableList(sortedConfigs);
	}
	
	private Collection<LineConfig> filterAvailableConfigs(
			final Collection<LineConfig> yetAvailableConfigs, 
			final Collection<LineConfig> configsLeft
			) {
		LOG.trace("filterAvailableConfigs(" +
				"yetAvailableConfigs=" + Arrays.toString(yetAvailableConfigs.toArray()) + ", " +
				"configsLeft=" + Arrays.toString(configsLeft.toArray()) +
				")");
		
		final Collection<LineConfig> configsWithProperOutgoings;
		if(yetAvailableConfigs.isEmpty() == true) {
			configsWithProperOutgoings = this.filter.filterNoOutgoingModules(configsLeft);
		} else {
			configsWithProperOutgoings = this.filter.filterWithTheseOutgoingModules(configsLeft, yetAvailableConfigs);
		}
		
		LOG.trace("filterAvailableConfigs(..) ... returning: " + Arrays.toString(configsWithProperOutgoings.toArray()));
		return configsWithProperOutgoings;
	}
	
}
